//----------------------------------------------------------------------------------------
//	 OverlapGraph.hh
//
//----------------------------------------------------------------------------------------
// $Id: //CBT-depot/CBT++/include/OverlapGraph.hh#1 $
//----------------------------------------------------------------------------------------
// $Log:$
//========================================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8.........9
//

#ifndef _OVERLAP_GRAPH
#define _OVERLAP_GRAPH

#include "LocalSTL.hh"
#include "CLibraryAdditions.hh"
#include "FileUtils.hh"
#include "HashUtils.hh"
#include "ParseUtils.hh"

#define TIMASK      0x07FFFFFF
#define DIRMASK     0x08000000
#define LESIGNMASK  0x10000000
#define RESIGNMASK  0x20000000

#define REMASK      0x000000FF
#define SPANMASK    0x0000FF00
#define LEMASK      0x00FF0000
#define SCOREMASK   0x7F000000
                   
// Status bits
#define MATEEDGEMASK 0x40000000

// Bit assignments
//
// mData0
//
// 0-26   TI
// 27     DIR
// 28     LESIGN
// 29     RESIGN
// 30     VISITED
// 31     UNUSED
//
// mData1
// 
// 0-7    RE
// 8-15   SPAN
// 16-23  LE
// 24-30  SCORE
// 31     UNUSED
//


//------------------------------------------------------------------------------
// * Edge
//------------------------------------------------------------------------------
//
class Edge{
public:
  int  mData0;
  int  mData1;
  unsigned char mData3;

  static int mMatePairScaleFactor;  

  void ClearMateEdge(){
	 int vcomp = ~MATEEDGEMASK;
	 mData0 = mData0 & vcomp;
  }

  void SetMateEdge(){
	 mData0 = mData0 | MATEEDGEMASK;
  }

  bool IsMateEdge(){
	 int vstatus = mData0 & MATEEDGEMASK;
	 if (vstatus) return(true);
	 else return(false);
  }

  //---------------------------------
  // * GetTI
  //---------------------------------
  // For now to reduce errors.  Later will make faster.
  int GetTI(){
	 int ti,span,score,le,re,dir;
	 GetValues(ti,span,score,le,re,dir);
	 return(ti);
  }

  //---------------------------------
  // * SetTI
  //---------------------------------
  void SetTI(int newti){
	 int ti,span,score,le,re,dir,nmercnt;
	 GetValues(ti,span,score,le,re,dir,nmercnt);
	 SetValues(newti,span,score,le,re,dir,nmercnt);
  }

  //---------------------------------
  // * InvertValues
  //---------------------------------
  void InvertValues(int newti){
	 int ti,span,score,le,re,dir;
	 GetValues(ti,span,score,le,re,dir);
	 
	 if (dir == 0){
		// if it is a same direction overlap simply reverse the sign of the extensions
		le = -le;
		re = -re;
	 }else{
		// if it is an opposite direction overlap, reverse the sign and order of the extensions
		le = -re;
		re = -le;
	 }	 
	 SetValues(newti,span,score,le,re,dir);
  }

  //---------------------------------
  // * SetValues
  //---------------------------------
  void SetValues(int ti,int span,int score,int le,int re,char dir)
  {
	 int idir;
	 if (dir == 'f') idir = 1;
	 else idir = 0;

	 SetValues(ti,span,score,le,re,idir);
  }

  //---------------------------------
  // * SetValues
  //---------------------------------
  void SetValues(int ti,int span,int score,int le,int re,char dir,int nmercnt)
  {
	 int idir;
	 if (dir == 'f') idir = 1;
	 else idir = 0;

	 SetValues(ti,span,score,le,re,idir);

	 if (nmercnt > 255) nmercnt=255;
	 mData3 = nmercnt;
  }

  void SetMateValues(int ti,int span,int score,int le,int re,int dir);

  void SetMateValues(int ti,int span,int score,int le,int re,int dir,int nmercnt){
	 SetMateValues(ti,span,score,le,re,dir);
	 if (nmercnt > 255) nmercnt=255;
	 mData3 = nmercnt;	 
  }

  void SetValues(int ti,int span,int score,int le,int re,int dir);
  void SetValues(int ti,int span,int score,int le,int re,int dir,int nmercnt){
	 SetValues(ti,span,score,le,re,dir);
	 if (nmercnt > 255) nmercnt=255;
	 mData3 = nmercnt;
  }

  void GetValues(int &ti,int &span, int &score, int &le, int &re, int &dir);

  void GetValues(int &ti,int &span, int &score, int &le, int &re, int &dir,int &nmercnt){
	 GetValues(ti,span,score,le,re,dir);
	 nmercnt = mData3;
  }

  void Print(ostream &fout){
	 int ti,span,score,le,re,dir,nmercnt;
	 GetValues(ti,span,score,le,re,dir,nmercnt);
	 cout<<ti<<" {"<<span<<","<<score<<","<<le<<","<<re<<","<<dir<<","<<nmercnt<<"} "<<flush;
  }

  void PrintBug(ostream &fout){
	 int ti,span,score,le,re,dir,nmercnt;
	 GetValues(ti,span,score,le,re,dir,nmercnt);
	 cout<<ti<<" {"<<span<<","<<score<<","<<le<<","<<re<<","<<dir<<","<<nmercnt<<"} "<<flush;
	 cout<<hex<<"\tmData0="<<mData0<<"\tmData1="<<mData1<<dec<<endl;
  }
};


//------------------------------------------------------------------------------
// * TIOverlapGraph
//------------------------------------------------------------------------------
// A graph that contains only TI's as node names.  This saves space by allowing
// the map to contain only integers (4 bytes) rathr than strings (about 20 bytes)
// and the edges to contain the TI's as 27 bit encodings. 
// 
class TIOverlapGraph{
public:

  // Maps ti values to multiple edgeIdxs
  Int2IntMultiMap  mTI2EIdxMap;

  // The actual edges.   
  vector<Edge>     mEdges;
 
  bool GetEdgeTI(Edge * pEdge,int &ti);

  bool Contains(int ti);
  void AddEdge(int ti,Edge &Edge);
  void AddEdges(int ti,vector<Edge> &Edges);
  void GetEdges(int ti,vector<Edge> &Edges);
  void AddEdges(int ti,vector<Edge> &Edges,vector<Edge*> &EdgePtrs);
  void GetEdges(int ti,vector<Edge*> &EdgePtrs);

  void Read(istream &fin);

};

//------------------------------------------------------------------------------
// * MixedOverlapGraph
//------------------------------------------------------------------------------
// This is a graph where the edges contain nodeIdxs, and where the input graph
// can have edges that go from a name (string) to a TI (int) or a TI (int) to 
// a name.  
//
//
class MixedOverlapGraph{
public:  

  MixedOverlapGraph(){
	 mNextNodeIdx = 0;
  }

  // mNextNodeIdx is also the number of nodes (reads) that are in graph. 
  int mNextNodeIdx;
  
  Int2IntMultiMap mNodeIdx2EIdxMap;
  vector<Edge> mEdges;

  // Several maps to go to and from node indices and either names
  // or ti's.   I could just treat ti's as string names, but that would
  // slow down access later when we have a numeric ti and need to convert it 
  // to a string ti in order to search.   These graphs are supposed to be small
  // so the space and speed of loading are minor issues compared to the speed
  // of access once loaded.  
  String2IntMap   mName2NodeIdxMap;
  Int2StringMap   mNodeIdx2NameMap;

  Int2IntMap      mTI2NodeIdxMap;
  Int2IntMap      mNodeIdx2TIMap;

  // Assumes edges are in form   MAAA1U10002 ->   gln|ti|23456{...}  gln|ti|66543 {...}
  //void ReadName2TI(istream &fin);

  int size(){
	 return(mNextNodeIdx);
  }

  void AddEdges(string &key, vector<Edge> &Edges);
  void AddEdgesAndInverse(string &key,vector<Edge> &Edges);


  void GetNodeEdges(int key,vector<Edge> &Edges);
  void GetNodeEdges(int key,vector<Edge*> &EdgePtrs);
  void GetTIEdges(string &key,vector<Edge> &Edges);
  void GetTIEdges(string &key,vector<Edge*> &EdgesPtrs);
  
  void GetNames(vector<string> &Names);

  bool GetEdgeTI(Edge * pEdge, int &ti);
  bool GetEdgeTI(Edge & Edge, int &ti);

  bool GetEdgeName(Edge * pEdge,string &name);
  bool GetEdgeName(Edge &Edge,string &name);

  // KJD Seems a bit of a kludge. 
  bool NameInTargetSet(vector<Edge*> &EdgePtrs,StringSet &TargetNames,
							  string &excludeName,int &foundIdx);

  bool NameInTargetSet(vector<Edge> &Edges,StringSet &TargetNames,
							  string &excludeName,int &foundIdx);

  // Reads in edges in form MAAA1U10002 ->   gln|ti|23456{...}  gln|ti|66543 {...} 
  // and also adds the inversion of those edges to the graph, edges like:
  // gln|ti|23456 -> MAAA1U10002 {...}
  // gln|ti|66543 -> MAAA1U10002 {...}
  void ReadName2TIPlusInverse(istream &fin);
};


//------------------------------------------------------------------------------
// * OverlapEdge
//------------------------------------------------------------------------------
// Edge for a plain overlap graph.  Sink is stored as a string and values are
// stored as ints (i.e. not space efficient).   
//
class OverlapEdge{
public:

  OverlapEdge(string sink,int span,int score,int le,int re,int dir){
	 SetValues(sink,span,score,le,re,dir);
  }

  void SetValues(string sink,int span,int score,int le,int re,int dir){
	 mSink = sink;
	 mSpan = span;
	 mScore = score;
	 mLE = le;
	 mRE = re;
	 mDir = dir;
  }

  string mSink;
  int mSpan;
  int mScore;
  int mLE;
  int mRE;
  int mDir;

};

//------------------------------------------------------------------------------
// * OverlapNode
//------------------------------------------------------------------------------
// Node in a plain overlap graph.  Keeps a vector of edges and a map of edge
// names for quick lookup. 
// 
class OverlapNode{
public:
  vector<OverlapEdge> mEdges;
  String2IntMap mSinkMap;

  void AddEdge(string sinkName,int span,int score,int le,int re,int dir){

	 // Modify existing edge...
	 if (mSinkMap.Contains(sinkName)){
		int edgeIdx = mSinkMap[sinkName];
		mEdges[edgeIdx].SetValues(sinkName,span,score,le,re,dir);
	 }else{
		// Or create a new edge...
		OverlapEdge E(sinkName,span,score,le,re,dir);
		int nextIdx = mEdges.size();
		mEdges.push_back(E);
		mSinkMap.Add(sinkName,nextIdx);
	 }
  }
};


//------------------------------------------------------------------------------
// * OverlapGraph
//------------------------------------------------------------------------------
// Plain overlap graph.  All node names are strings.  Edges store string names. 
// Not for space efficient storage.  
//
class OverlapGraph{
public:
  
  vector<OverlapNode> mNodes;
  String2IntMap  mNodeMap;
  
  void AddEdge(string &source,string &sink,int span,int score,int le,int re,int dir);
  
  int GetScore(string &source,string &sink);
  bool EdgeExists(string &source,string &sink);

  void Print(ostream &fout);
};


#endif 


